package com.holly.unit.deform;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.holly.unit.db.api.factory.PageFactory;
import com.holly.unit.db.api.factory.PageResultFactory;
import com.holly.unit.db.api.pojo.druid.DruidProperties;
import com.holly.unit.db.api.pojo.page.PageResult;
import com.holly.unit.db.api.util.DatabaseUtil;
import com.holly.unit.deform.api.DeformBaseInfoApi;
import com.holly.unit.deform.api.constants.DeformConstants;
import com.holly.unit.deform.api.exception.DeformException;
import com.holly.unit.deform.api.exception.enums.DeformExceptionEnum;
import com.holly.unit.deform.api.pojo.base.DesignFormDTO;
import com.holly.unit.deform.api.pojo.base.DictModelDTO;
import com.holly.unit.deform.api.pojo.base.TranslateDataDTO;
import com.holly.unit.deform.api.pojo.data.DesignFormDataDTO;
import com.holly.unit.deform.api.pojo.online.pojo.ColumnInfo;
import com.holly.unit.deform.context.DeformContext;
import com.holly.unit.deform.entity.DesignForm;
import com.holly.unit.deform.entity.DesignFormData;
import com.holly.unit.deform.service.DeformBaseInfoService;
import com.holly.unit.deform.service.DeformDataService;
import com.holly.unit.deform.util.DatabaseDeFormUtil;
import com.holly.unit.deform.util.JsonUtil;
import com.holly.unit.es.api.EsApi;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 类描述: 表单设计基本信息操作器
 *
 * @author fxr
 * @version 1.0.0
 * @date 2022/4/5 10:22
 */
@Slf4j
public class DeformBaseInfoOperator implements DeformBaseInfoApi<DesignForm>{

    private DeformBaseInfoService deformBaseInfoService = DeformContext.deformBaseInfoService();

    private DeformDataService deformDataService = DeformContext.deformDataService();



    private EsApi esApi = DeformContext.esApi();

    @Resource
    private DruidProperties druidProperties;

    @Override
    public void saveOneToMany(DesignFormDTO designFormDTO) {
        DesignForm designForm = new DesignForm();
        BeanUtil.copyProperties(designFormDTO,designForm);
        deformBaseInfoService.saveMain(designForm);
    }

    @Override
    public void updateOneToMany(DesignFormDTO designFormDTO, List<DesignFormDataDTO> designFormDataList) {
        DesignForm designForm = new DesignForm();
        List<DesignFormData> designFormDatas = new ArrayList<>();
        BeanUtil.copyProperties(designFormDTO,designForm);
        BeanUtil.copyProperties(designFormDataList,designFormDatas);
        deformBaseInfoService.updateMain(designForm,designFormDatas);
    }

    @Override
    public void delOneToMany(String id) {
        deformBaseInfoService.delMain(id);
    }

    @Override
    public void delBatchOneToMany(Collection<? extends Serializable> idList) {
        if (idList == null || idList.size() == 0) {
            log.error(DeformExceptionEnum.DEFORM_DEL_PARAM_ERROR.getUserTip());
            throw new DeformException(DeformExceptionEnum.DEFORM_DEL_PARAM_ERROR);
        }
        deformBaseInfoService.delBatchMain(idList);
    }

    @Override
    public DesignFormDTO getByCode(String desformCode) {
        DesignForm designForm = deformBaseInfoService.getByCode(desformCode);
        if (designForm == null) {
            log.error(DeformExceptionEnum.DEFORM_QUERY_BY_CODE_ERROR.getUserTip());
            throw new DeformException(DeformExceptionEnum.DEFORM_QUERY_BY_CODE_ERROR,desformCode);
        }
        DesignFormDTO designFormDTO = new DesignFormDTO();
        BeanUtil.copyProperties(designForm,designFormDTO);
        return designFormDTO;
    }

    @Override
    public DesignFormDTO getById(String id) {
        DesignForm designForm = deformBaseInfoService.getById(id);
        if (designForm == null) {
            log.error(DeformExceptionEnum.DEFORM_QUERY_BY_ID_ERROR.getUserTip());
            throw new DeformException(DeformExceptionEnum.DEFORM_QUERY_BY_ID_ERROR,id);
        }
        DesignFormDTO designFormDTO = new DesignFormDTO();
        BeanUtil.copyProperties(designForm,designFormDTO);
        return designFormDTO;
    }

    @Override
    public void updateById(DesignForm designForm) {
        //设计表单保存
        if(designForm!=null && designForm.getDesformDesignJson()!=null){
            //自动生成表单生成数据库表或修改
            if(designForm.getType() == 2){
                JSONArray list = null;
                String desformDesignStr = designForm.getDesformDesignJson();
                JSONObject json = JSONObject.parseObject(desformDesignStr);
                if(json.get("list")!=null){
                    list = (JSONArray) json.get("list");
                }
                //生成数据库表
                if(StrUtil.isEmpty(designForm.getCgformCode())){
                    //组装创建表sql
                    Map<String, ColumnInfo> dataTable = JsonUtil.createDataTable(list);
                    if(dataTable != null){
                        String sql = JsonUtil.javaCreateTable(dataTable,designForm.getDesformCode(),designForm.getDesformName());
                        DatabaseUtil.createDataTable(druidProperties,sql);
                        designForm.setCgformCode(designForm.getDesformCode());
                    }
                }else {//修改数据库表
                    List<String> alterList = new ArrayList<>();
                    String alterSql = "alter table  "+designForm.getCgformCode()+" ";
                    //json组装
                    Map<String, ColumnInfo> dataTable = JsonUtil.createDataTable(list);
                    //查询表字段信息
                    List<ColumnInfo> originalTableColumn = DatabaseDeFormUtil.findOriginalTableColumn(druidProperties, designForm.getCgformCode());
                    Map<String, ColumnInfo> maps = originalTableColumn.stream().collect(Collectors.toMap(ColumnInfo::getFieldName, Function.identity()));
                    for (String columnName : dataTable.keySet()) {
                        //遍历配置表 判断原表列是否包含当前列
                        if(!maps.containsKey(columnName)){
                            //表如果不存在该列，则要对表做修改、增加、删除该列动作 此处无法处理删除的列，因为在这个循环中无法获得该列
                            ColumnInfo cgFormColumnMeta = dataTable.get(columnName);
                            alterList.add(alterSql+JsonUtil.getAddColumnSql(cgFormColumnMeta));
                        }else {
                            //已经存在,判断是否类型、是否为空、字段备注,如果有修改则处理修改
                            ColumnInfo dataColumnMeta = dataTable.get(columnName);
                            ColumnInfo cgFormColumnMeta = maps.get(columnName);
                            //如果不相同，则表示有变化，则需要修改
                            if (!dataColumnMeta.equalsByDataType(cgFormColumnMeta)) {
                                alterList.add(alterSql+JsonUtil.getUpdateColumnSql(dataColumnMeta));
                            }
                        }
                    }
                    //删除数据库的列
                    for (String columnName : maps.keySet()) {
                        List result = Arrays.asList(JsonUtil.pageFilterFields.split(","));
                        if (!dataTable.containsKey(columnName) && !result.contains(columnName)) {
                            alterList.add(alterSql+JsonUtil.getDropColumnSql(columnName));
                        }
                    }
                    if(alterList.size() > 0){
                        //修改数据库表字段
                        DatabaseUtil.executeDDL(druidProperties,alterList);
                    }
                }
                if(json.get("config")!=null){
                    JSONObject config = json.getJSONObject("config");
                    if(StrUtil.isEmpty(config.getString("onlineForm"))){
                        config.put("onlineForm",designForm.getCgformCode());
                        json.put("config",config);
                        designForm.setDesformDesignJson(json.toJSONString());
                    }
                }
            }
        }
        boolean ans = deformBaseInfoService.updateById(designForm);
        if (!ans) {
            log.error(DeformExceptionEnum.DEFORM_EDIT_ERROR.getUserTip());
            throw new DeformException(DeformExceptionEnum.DEFORM_EDIT_ERROR);
        }
    }

    /***
     * 判断是否是字典类型，如果是就查询字典
     * @param designFormDTO
     * @return
     */
    @Override
    public DesignFormDTO queryAllDictItem(DesignFormDTO designFormDTO) {
        DesignFormDTO designFormDTO1 = new DesignFormDTO();
        DesignForm designForm = new DesignForm();
        BeanUtil.copyProperties(designFormDTO,designForm);
        DesignForm designForm1 = deformBaseInfoService.queryAllDictItem(designForm);
        BeanUtil.copyProperties(designForm1,designFormDTO1);
        return designFormDTO;
    }

    @Override
    public Map<String, List<DictModelDTO>> translateColumns(List<TranslateDataDTO> translateDataDTOList) {
        return deformBaseInfoService.translateColumns(translateDataDTOList);
    }

    @Override
    public boolean setMobileView(String parentCode, String desformCode) {
        DesignForm updateEntity = new DesignForm();
        QueryWrapper<DesignForm> updateWrapper = new QueryWrapper<>();
        // 去掉其他的移动模板
        updateEntity.setIzMobileView(DeformConstants.IS_MOBILE_VIEW_N);
        updateWrapper.eq("iz_mobile_view", DeformConstants.IS_MOBILE_VIEW_Y).eq("desform_code", parentCode).or().eq("parent_code", parentCode);
        deformBaseInfoService.update(updateEntity, updateWrapper);
        // 设置新的移动模板
        updateEntity.setIzMobileView(DeformConstants.IS_MOBILE_VIEW_Y);
        updateWrapper = new QueryWrapper<DesignForm>().eq("desform_code", desformCode);
        deformBaseInfoService.update(updateEntity, updateWrapper);
        return true;
    }

    @Override
    public List<DesignFormDTO> fetchList(QueryWrapper<?> queryWrapper) {
        List<DesignFormDTO> dtos = new ArrayList<>();
        List<DesignForm> list = deformBaseInfoService.list((Wrapper<DesignForm>) queryWrapper);
        list.stream().forEach(entity->{
            DesignFormDTO dto = new DesignFormDTO();
            BeanUtil.copyProperties(entity,dto);
            dtos.add(dto);
        });
        return dtos;
    }

    @Override
    public PageResult<DesignFormDTO> pageList(QueryWrapper<?> queryWrapper) {
        Page<DesignForm> page = deformBaseInfoService.page(PageFactory.defaultPage(),(Wrapper<DesignForm>)queryWrapper);
        PageResult<DesignForm> pageResult = PageResultFactory.createPageResult(page);
        List<DesignFormDTO> dtos = new ArrayList<>();
        pageResult.getRows().stream().forEach(entity->{
            DesignFormDTO dto = new DesignFormDTO();
            BeanUtil.copyProperties(entity,dto);
            dtos.add(dto);
        });
        return createDtoPageResult(pageResult, dtos);
    }


    @Override
    public int fetchChildNodeCount(String parentId) {
        QueryWrapper<DesignForm> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        return deformBaseInfoService.count(queryWrapper);
    }

    @Override
    public boolean hasChild(String parentId) {
        return fetchChildNodeCount(parentId)>0;
    }

    @Override
    public void redoAllIndex(String rowIds) {
        try {
            long begin = System.currentTimeMillis();
            log.debug("-- 已开始快速重置ES索引数据");
            LambdaQueryWrapper<DesignFormData> queryWrapper = new LambdaQueryWrapper<DesignFormData>();
            if(StrUtil.isNotEmpty(rowIds)){
                queryWrapper.in(DesignFormData::getDesformId,rowIds.split(","));
            }
            List<DesignFormData> dataList = deformDataService.list(queryWrapper);
            int successCount = 0, failCount = 0;
            for (int i = 0; i < dataList.size(); i++) {
                DesignFormData dataItem = dataList.get(i);
                String desformCode = dataItem.getDesformCode();
                log.debug("---- 正在重置：" + desformCode + "（第 " + (i + 1) + " 个/共 " + dataList.size() + " 个）");
                JSONObject dataJson = JSON.parseObject(dataItem.getDesformDataJson());
                if (esApi.saveOrUpdate(desformCode, "design_form", dataItem.getId(), dataJson)) {
                    successCount++;
                } else {
                    failCount++;
                }
            }
            long end = System.currentTimeMillis();
            String msg;
            if (failCount == 0) {
                msg = "快速重置ES索引全部成功!";
            } else {
                msg = String.format("快速重置ES索引：成功了%s条，失败了%s条", successCount, failCount);
                log.debug("-- " + msg);
                log.debug("-- 总耗时：" + (end - begin) + " ms");
                throw new DeformException(DeformExceptionEnum.DEFORM_REDOALLINX_BUG,successCount,failCount);
            }
            log.debug("-- " + msg);
            log.debug("-- 总耗时：" + (end - begin) + " ms");
        } catch (Exception e) {
            e.printStackTrace();
            throw new DeformException(DeformExceptionEnum.DEFORM_REDOALLINX_ERROR);
        }
    }

    @Override
    public void redoAllIndexForce(String rowIds) {
        try {
            log.debug("-- 已开始强制重置ES索引");
            LambdaQueryWrapper<DesignForm> queryWrapper = new LambdaQueryWrapper<DesignForm>();
            if(StrUtil.isNotEmpty(rowIds)){
                queryWrapper.in(DesignForm::getId,rowIds.split(","));
            }
            List<DesignForm> allForm = deformBaseInfoService.list(queryWrapper);
            long begin = System.currentTimeMillis();
            for (int i = 0; i < allForm.size(); i++) {
                DesignForm formItem = allForm.get(i);
                String desformCode = formItem.getDesformCode();
                log.debug("---- 正在重置：" + desformCode + "（第 " + (i + 1) + " 个/共 " + allForm.size() + " 个）");
                esApi.removeIndex(desformCode);
                esApi.createIndex(desformCode);
            }
            long end = System.currentTimeMillis();
            log.debug("-- 强制重置ES索引完成，即将开始快速重置数据");
            log.debug("-- 总耗时：" + (end - begin) + " ms");
            this.redoAllIndex(rowIds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DeformException(DeformExceptionEnum.DEFORM_REDOALLINXFORCE_ERROR);
        }
    }

    @Override
    public boolean checkCode(DesignFormDTO desformCode) {
        return deformBaseInfoService.checkCode(desformCode);
    }

    private PageResult<DesignFormDTO> createDtoPageResult(PageResult<DesignForm> pageResult, List<DesignFormDTO> dtos) {
        PageResult<DesignFormDTO> res = new PageResult<>();
        res.setRows(dtos);
        res.setTotalRows(Convert.toInt(pageResult.getTotalRows()));
        res.setPageNo(pageResult.getPageNo());
        res.setPageSize(pageResult.getPageSize());
        res.setTotalPage(PageUtil.totalPage(pageResult.getTotalRows(), pageResult.getPageSize()));
        return res;
    }


}
